var sparql = new jQSparql();	
var prefix = sparql.prefix() +" #E \n";
var responseData;
var gJSON;
var wrapper;
var submittedQuery = "";
var sparqlEndpoints = ["http://data.aalto.fi/sparql","http://data.uni-muenster.de/sparql","http://sparql.data.southampton.ac.uk/","http://data.open.ac.uk/query","http://resrev.ilrt.bris.ac.uk/data-server-workshop/sparql"];
var parsedQuery = null;
var parIds = null;
var vH = 250;
var vW = 150;
var newInit = true;

$('#prefix').html(sparql.prefixToString().replace(/\n/g,"<br/>"));

google.load("visualization", "1", {packages:["charteditor"],language: "en"});


google.setOnLoadCallback(function() {
	$("#add").click();
	$('#load').css("display", "none");
	 if(window.location.hash) {
		var decodedHash = decode(window.location.hash.substr(1));
		decodedData = decodedHash.substr(0,decodedHash.indexOf("?query="));
		decodedQuery = decodedHash.substring(decodedHash.indexOf("?query=")+7,decodedHash.indexOf("?e="));
		decodedType = parseInt(decodedHash.charAt(decodedHash.indexOf("?e=")+3));
		decodedEndpoints = decodedHash.substring(decodedHash.indexOf("?e=")+4,decodedHash.indexOf("?x="));
		decodedWH = decodedHash.substr(decodedHash.indexOf("?x=")+3);
		
		vW=decodedWH.split("x")[0];
		vH=decodedWH.split("x")[1];
		
		switch(decodedType) {
			case 1: $("input[id='flat']").attr('checked', true); break;
			case 2: $("input[id='group']").attr('checked', true); break;
			case 3: $("input[id='col']").attr('checked', true); break;
			default: $("input[id='flat']").attr('checked', true); break;
		}
				
		if(decodedData != null && decodedQuery!= null && decodedEndpoints != null) {
			var arr = decodedEndpoints.split(",");
			$("#endpoints").empty();
			for(e in arr) $("#endpoints").append("<li contenteditable='true'>"+arr[e]+"</li>");
			submitQuery(decodedQuery,decodedData);
			hideQuery();
		}
		else {
			showModal("Url decoding failed","There seems to be something wrong with the url");
			newQuery();
		}
	   }
   else {
	   newQuery();
	} 
});

var queries = [
"SELECT (COUNT(?s) as ?c) WHERE { ?s a ?o FILTER(REGEX(STR(?o), 'http://xmlns.com/foaf/0.1/'))}",
"SELECT DISTINCT ?g (count(?p) as ?triples) WHERE { GRAPH ?g { ?s ?p ?o } } GROUP BY ?g",
"SELECT ?class (COUNT(?s) AS ?count) { ?s a ?class } GROUP BY ?class ORDER BY ?count",
"SELECT ?p (COUNT(?p) AS ?count ) { [a ?class] ?p ?o } GROUP BY ?p ORDER BY ?count",
"SELECT (COUNT(?s4) as ?gr) (COUNT(?s3) as ?bibo) (COUNT(?s2) as ?aiiso) (COUNT(?s) as ?foaf) WHERE { {?s a ?o FILTER(REGEX(STR(?o), 'http://xmlns.com/foaf/0.1/'))} UNION { ?s2 a ?o2 FILTER(REGEX(STR(?o2), 'http://purl.org/vocab/aiiso/schema#'))} UNION { ?s3 a ?o3 FILTER(REGEX(STR(?o3), 'http://purl.org/ontology/bibo/'))  } UNION { ?s4 a ?o4 FILTER(REGEX(STR(?o4), 'http://purl.org/goodrelations/v1#'))  }}"
];

$('#querySelect').change(function() {
	decodedData = null; wrapper = null;
	if($('#querySelect option:selected').val()<0) {
	$('#area').val(queries[0]);
	}
	else {
    $('#area').val(queries[$('#querySelect option:selected').val()]);
	}
});


function submitQuery(queryString,decodedData) {
	
	var arr = $("#endpoints li").map(function(){ return $(this).text(); }).get();
	
	  if(arr.length==1) {

	sparql.query(arr[0],queryString,null,"sproxy.php?service-uri=").done(function(data) {
	//FIXME: comment this out
	//data = $.parseJSON(data); // For debugging only
	$('#load').css("display", "none");
	if(data.results == undefined || data.results.bindings.length>0) {
		responseData = data;
		submittedQuery = queryString;
		var gTable = sparql.getGoogleDataTable(data);
		gJSON = gTable.toJSON();
		
		if(decodedData != null) initDecoded(decodedData);
		else init();
		
	} else { gJSON = null;
	showModal("Empty results","SPARQL-query did not return any results");
	$('#queryForm').css("display", "inherit");
}
}).fail(function(request, status, error) {
	$("#endpoints li").css("color","red");
	showModal("Request failed",request.responseText);
	$('#load').css("display", "none");
	$('#queryForm').css("display", "inherit"); 
});

} else if(arr.length>1) {

	sparql.multiQuery(arr,queryString,"sproxy.php?service-uri=").done(function(data) {
		submittedQuery = queryString;
		responseData = data;
	    $('#load').css("display", "none");
	    var gTable;
	    
	    var method = parseInt($("input[name='options']:checked").val());

	    switch(method) {
			case 1: gTable = sparql.combineToGoogleDataTableFLAT(data); break;
			case 2: {
				try { 
				 var groupBy = $("#groupBy").val();
				 var methodTo = $("#to").val();
				 groupBy = parseInt(parIds[groupBy]);
				 methodTo = parseInt(parIds[methodTo]);
				 gTable = sparql.groupAndMethod(data,groupBy,$("#groupMethod").val(),methodTo);  break;
				 break;
			 } catch(err) {
			  alert("Error! Could not perform the method. See log.");
			  console.log(err);
			  showQuery();
			  break;
			 }
			 }
			case 3: gTable = sparql.combineToGoogleDataTable(data); break;
			default: gTable = sparql.combineToGoogleDataTableFLAT(data); break;
		}
		console.log(gTable);
		gJSON = gTable.toJSON();
		
		if(decodedData != null) initDecoded(decodedData);
		else init();
	}).fail(function(err)  {
		showQuery();
		$('#load').css("display", "none");
	});

} else { 
	alert("No endpoints defined!"); 	
    showQuery();
}}

$('#query').click(function() {
  var q = $("#area").val();

  try {
	parsedQuery = sparqlParser.parse(q);
	var qType = parsedQuery.units[0].kind;
	var parameters = parsedQuery.units[0].projection;
	parIds=[];
	for(i in parameters) if(parameters[i].kind=="var") parIds["?"+parameters[i].value.value]=i; else  parIds["?"+parameters[i].alias.value]=i;
	hideQuery();
  }
  catch(e){ 
	  hideQuery(); 
	  console.log(e);
	  //FIXME: SPARQL-parser not working with BINDINGS
	  //showModal(e.name,"Line "+e.line+": "+e.message);
  }

  if(wrapper!=null) submitQuery(prefix+q,wrapper.toJSON());
  else if(decodedData != null) submitQuery(prefix+q,decodedData);
  else submitQuery(prefix+q);

  
  return false;
});

function showQuery() {
    $('#load').css("display", "none");
	$('#queryForm').css("display", "inherit");
	$('#addendpoints').css("display", "inherit");
	$('#editChart').css("visibility", "hidden");
	$('#chartHolder').css("display", "none");
	$('#confJSON').css("display", "none");
}

function hideQuery() {
  $('#load').css("display", "inherit");
  $('#queryForm').css("display", "none");
  $('#addendpoints').css("display", "none");
}

function init() {
	$('#editChart').css("visibility", "visible");
	$('#chartHolder').css("display", "inherit");
 
  wrapper = new google.visualization.ChartWrapper({
    chartType: 'Table',
    dataTable: new google.visualization.DataTable(gJSON),
    options: {title: 'VISUalisation'},
    containerId: 'visualization'
  });
  
  drawWrapper();
  
}

function initDecoded(decodedData) {
	newInit = false;
	$('#editChart').css("visibility", "visible");
	$('#chartHolder').css("display", "inherit");
	wrapper = new google.visualization.ChartWrapper(decodedData);
	wrapper.setDataTable(gJSON);
	
	google.visualization.events.addListener(wrapper, 'error', function(err) { console.log(err); openEditor();});
	$("#visualization").removeClass('newvisualization');
	$("#visualization").width(vW);
	$("#visualization").height(vH);
	drawWrapper();
	$('#load').css("display", "none");
}

function b64en(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var n,r,i,s,o,u,a,f,l=0,c=0,h="",p=[];if(!e){return e}do{n=e.charCodeAt(l++);r=e.charCodeAt(l++);i=e.charCodeAt(l++);f=n<<16|r<<8|i;s=f>>18&63;o=f>>12&63;u=f>>6&63;a=f&63;p[c++]=t.charAt(s)+t.charAt(o)+t.charAt(u)+t.charAt(a)}while(l<e.length);h=p.join("");var d=e.length%3;return(d?h.slice(0,d-3):h)+"===".slice(d||3)}
function encode(str) { return b64en(RawDeflate.deflate(unescape(encodeURIComponent(str))));}

function b64de(e){var t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";var n,r,i,s,o,u,a,f,l=0,c=0,h="",p=[];if(!e){return e}e+="";do{s=t.indexOf(e.charAt(l++));o=t.indexOf(e.charAt(l++));u=t.indexOf(e.charAt(l++));a=t.indexOf(e.charAt(l++));f=s<<18|o<<12|u<<6|a;n=f>>16&255;r=f>>8&255;i=f&255;if(u==64){p[c++]=String.fromCharCode(n)}else if(a==64){p[c++]=String.fromCharCode(n,r)}else{p[c++]=String.fromCharCode(n,r,i)}}while(l<e.length);h=p.join("");return h}
function decode(str) { return decodeURIComponent(escape(RawDeflate.inflate(b64de(str))));}

var editorOpen = false;

function openEditor() {
	if(!editorOpen) {
		editorOpen=true;
      // Handler for the "Open Editor" button.
      var editor = new google.visualization.ChartEditor();

      google.visualization.events.addListener(editor, 'ok',
        function() {
			editorOpen=false
    	   	// Just draw the #(=/"#(? thing
    	    wrapper = editor.getChartWrapper();
    	        	    
			drawWrapper();
      });
            
      google.visualization.events.addListener(editor, 'cancel',
        function() {
			editorOpen=false;
		if(wrapper!=null) {
			drawWrapper();
		} else newQuery();
		});
	  
      editor.openDialog(wrapper);
      
  }
 }
 
 // Draws wrapper to visualization div
 function drawWrapper() {
	 
	wrapper.draw(document.getElementById('visualization'));

    if(wrapper.getChartType()=="Table") {
     google.visualization.events.addListener(wrapper.getChart(), 'sort',
      function(event) {
		wrapper.getDataTable().sort([{column: event.column, desc: !event.ascending}]);
      });
  }
	
	var title = wrapper.getChartName();
	if(title != null && title.length>1) $('#title').html(title);
	else  $('#title').html("");
	$('#editChart').css("visibility", "visible");
	$('#chartHolder').css("display", "inherit");
	

	
	createHash();
 }
 
 // Creates neat hash from google chart wrapper and sparql-query
 function createHash() {
		var wrapJSON = $.parseJSON(wrapper.toJSON());
		delete wrapJSON["dataTable"];
		//removeNulls(wrapJSON);
		//removeEmptyObjects(wrapJSON);
		var packed = JSON.stringify(wrapJSON,undefined,2);
		packed+="?query=";
		packed+=submittedQuery;
		packed+="?e="+$("input[name='options']:checked").val();
		packed+=$("#endpoints li").map(function(){ return $(this).text(); }).get().join();
		packed+="?x="+parseInt($("#visualization").width())+"x"+parseInt($("#visualization").height());		
		packed = encode(packed);
		window.location.hash="#"+packed; 
		
		$("#visualization").width($("#visualization").width());
		$("#visualization").height($("#visualization").height()); 
		vW = $("#visualization").width();
		vH = $("#visualization").height();

 }
 
$("#add").click(function() { 

	var e = $("<li contenteditable='true' class='endpoint'>http://</li>");

	var length = $("#endpoints li").map(function(){ return $(this).text(); }).get().length;

	if(length<sparqlEndpoints.length) 
	e = $("<li id="+sparqlEndpoints[length].replace(/[^\w\s]/gi, '')+" contenteditable='true' class='endpoint'>"+sparqlEndpoints[length]+"</li>");

	e.focusout(function() {
		if($(this).text().length<1) $(this).remove();
		else e.attr('id', this.innerHTML.replace(/[^\w\s]/gi, '')); 
	});
	
	$("#endpoints").append(e);
	if(length+1>1) $("#radios").show();
	
});

$("#remove").click(function() {
 $("#endpoints li:last").remove();
 var length = $("#endpoints li").map(function(){ return $(this).text(); }).get().length;
 if(length<=1) $("#radios").hide();
});

$('.endpoint').focusout(function(){
	if($(this).text().length<1) $(this).remove();
	else $(this).attr('id', this.innerHTML.replace(/[^\w\s]/gi, ''));
});

$('#prefixify').mousedown(function() {
    sparql.pfix=!sparql.pfix;
});
 
 // encodes current wrapper and opens old query
 function editQuery() {
	if(submittedQuery != null && submittedQuery.length > 1) {
		$('#area').val(submittedQuery.substring(submittedQuery.indexOf('#E')+4));
		showQuery();
	} else {
		showModal("Query error!","There seems to be something wrong with the current query!");
		newQuery();
}
}

function dataTableToCSV() {
	// Modified from https://gist.github.com/pilate/1477368
    dataTable_arg = wrapper.getDataTable();
    var dt_cols = dataTable_arg.getNumberOfColumns();
    var dt_rows = dataTable_arg.getNumberOfRows();
    
    var csv_cols = [];
    var csv_out;
    
    // Iterate columns
    for (var i=0; i<dt_cols; i++) {
        // Replace any commas in column labels
        csv_cols.push(dataTable_arg.getColumnLabel(i).replace(/,/g,""));
    }
    
    // Create column row of CSV
    csv_out = csv_cols.join(",")+"\n";
    
    // Iterate rows
    for (i=0; i<dt_rows; i++) {
        var raw_col = [];
        for (var j=0; j<dt_cols; j++) {
            // Replace any commas in row values
            raw_col.push(dataTable_arg.getFormattedValue(i, j, 'label').replace(/,/g,""));
        }
        // Add row to CSV text
        csv_out += raw_col.join(",")+"\n";
    }
 
 window.open('data:text/csv;charset=utf-8,' + encodeURIComponent(csv_out));
 
  //  showModal("Exported csv",csv_out);
}


  
	function selectText(objId) {
		fnDeSelect();
		if (document.selection) {
		var range = document.body.createTextRange();
 	        range.moveToElementText(document.getElementById(objId));
		range.select();
		}
		else if (window.getSelection) {
		var range = document.createRange();
		range.selectNode(document.getElementById(objId));
		window.getSelection().addRange(range);
		}
	}
	
	function fnDeSelect() {
		if (document.selection) document.selection.empty(); 
		else if (window.getSelection)
                window.getSelection().removeAllRanges();
	}

function showModal(header,message,additional) {
	if(additional!=undefined) $('#modal-add').html(additional);
	else $('#modal-add').empty();
	$('#modal-header').html(header);
	$('#modal-body').html(message);
	$('#modal').modal('show');
}

function manualEdit() {
	if(wrapper != null) {
		var op = wrapper.getOptions();
		showModal("Manual edit","<div id='editMe'>"+JSON.stringify(op)+"</div>","<a target='_blank' href='https://developers.google.com/chart/interactive/docs/reference'>Link to Google JSON reference</a>");
		
		 $('#editMe').click(function() {
 this.contentEditable='true';
});
 
$('#editMe').focusout(function(){
	var obj = $.parseJSON(this.innerHTML);
	wrapper.setOptions(obj);
	wrapper.draw(document.getElementById('visualization'));
	createHash();
	//drawWrapper();
});
		
	}
 }
 

function exportWrapper() {
	showModal("Exported wrapper JSON",wrapper.toJSON());
}

function log() {
	alert("Response data is logged!");
	console.log(responseData);
}

function publish() {	
	var packed = encode(wrapper.toJSON());
    var hashLocation =  window.location.protocol + '//' + window.location.host + "/chart"+"#"+packed;
    
    if(hashLocation.length>5000) showModal("Dataset is too big","Dataset is too large to publish in url-based static visualization!");
    else {//window.open(hashLocation);
    console.log(hashLocation);
 $.ajax({
        url: 'https://www.googleapis.com/urlshortener/v1/url?shortUrl=http://goo.gl/fbsS&key=AIzaSyBMqvwI0ApUcVsmQSV3E3iXANWzxLXVdd8',
        type: 'POST',
        contentType: 'application/json; charset=utf-8',
        data: '{ longUrl: "' + hashLocation +'"}',
        dataType: 'json',
        context: $("#message"),
        success: function(response) {
			showModal("Link to static chart","Static chart is published in <a href='"+response.id+"'>"+response.id+"</a>. <i>(Notice that static charts will be rendered much faster from the results, but the SPARQL-query will be lost.)</i>");
        }
     });
 }
     
	
}

// Deletes old wrapper and open new query form
 function newQuery() {
   decodedData = null;
   wrapper = null;
   window.location.hash="";
   $("#message").empty();
   showQuery();
 }


// Resize functionality
 
 function resize() {
	$("#visualization").width(250);
    $("#visualization").height(150);
	$("#visualization").addClass("newvisualization");
 }
 
 
 $("#visualization").mouseup(function() {
	 if( $("#visualization").hasClass("newvisualization") ) {
		 $("#visualization").removeClass("newvisualization");
		drawWrapper();
	}
 });
 
 
